﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    public struct GeoCoord
    {
        /// <summary>
        /// 经度
        /// </summary>
        public double Longitude;
        /// <summary>
        /// 纬度
        /// </summary>
        public double Latitude;
        /// <summary>
        /// 高度
        /// </summary>
        public double Altitude;
    }
    /// <summary>
    /// exif
    /// </summary>
    public class ImageGeoCoordUtil
    {
        public static GeoCoord ParseLonLat(string image)
        {
            GeoCoord geoCoord = new GeoCoord();
            string s_GPS = "";
            //载入图片
            using (Image objImage = Image.FromFile(image))
            {
                //取得所有的属性(以PropertyId做排序)
                var propertyItems = objImage.PropertyItems.OrderBy(x => x.Id).ToArray();
                //暂定纬度N(北纬)
                char chrGPSLatitudeRef = 'N';
                //暂定经度为E(东经)
                char chrGPSLongitudeRef = 'E';
                foreach (PropertyItem objItem in propertyItems)
                {
                    //只取Id范围为0x0000到0x001e
                    if (objItem.Id >= 0x0000 && objItem.Id <= 0x001e)
                    {
                        //objItem.Id = 0x0002;
                        switch (objItem.Id)
                        {
                            case 0x0000:
                                var query = from tmpb in objItem.Value select tmpb.ToString();
                                string sreVersion = String.Join(".", query.ToArray());
                                s_GPS += sreVersion + "+";
                                break;
                            case 0x0001:
                                chrGPSLatitudeRef = BitConverter.ToChar(objItem.Value, 0);
                                s_GPS += chrGPSLatitudeRef + "+";
                                break;
                            case 0x0002:
                                if (objItem.Value.Length == 24)
                                {
                                    double dblGPSLatitude = PaseGps(objItem.Value);
                                    //计算经纬度数值, 如果是南纬, 要乘上(-1)   
                                    dblGPSLatitude = dblGPSLatitude * (chrGPSLatitudeRef.Equals('N') ? 1 : -1);
                                    geoCoord.Latitude = dblGPSLatitude;

                                    //纬度+经度
                                    s_GPS += dblGPSLatitude + "+";
                                }
                                break;
                            case 0x0003:
                                //透过BitConverter, 将Value转成Char('E' / 'W')   
                                //此值在后续的Longitude计算上会用到   
                                chrGPSLongitudeRef = BitConverter.ToChar(objItem.Value, 0);
                                break;
                            case 0x0004:
                                if (objItem.Value.Length == 24)
                                {
                                    double dblGPSLongitude = PaseGps(objItem.Value);
                                    //计算精度的数值, 如果是西经, 要乘上(-1)   
                                    dblGPSLongitude = dblGPSLongitude * (chrGPSLongitudeRef.Equals('E') ? 1 : -1);
                                    geoCoord.Longitude = dblGPSLongitude;
                                }
                                break;
                            case 0x0005:
                                string strAltitude = BitConverter.ToBoolean(objItem.Value, 0) ? "0" : "1";
                                break;
                            case 0x0006:
                                if (objItem.Value.Length == 8)
                                {
                                    double dblAltitude = ExifBitConverter.ToURational(objItem.Value.Take(8).ToArray());
                                    geoCoord.Altitude = dblAltitude;
                                }
                                break;
                            default:
                                break;
                        }
                    }
                }
            }

            return geoCoord;
        }

        private static double PaseGps(byte[] bytes)
        {
            double d = ExifBitConverter.ToURational(bytes.Take(8).ToArray());
            double m = ExifBitConverter.ToURational(bytes.Skip(8).Take(8).ToArray());
            double s = ExifBitConverter.ToURational(bytes.Skip(16).Take(8).ToArray());
            return (s / 60 + m) / 60 + d; ;
        }
    }

    public class ExifBitConverter
    {
        /// <summary>
        /// Converts 8 bytes to an unsigned rational using the current byte aligns
        /// </summary>
        /// <seealso cref="ToRational"/>
        public static double ToURational(byte[] data)
        {
            //degrees(将byte[0]~byte[3]转成uint, 除以byte[4]~byte[7]转成的uint)   
            var fraction = ToURationalFraction(data);

            return fraction[0] / (double)fraction[1];
        }

        /// <summary>
        /// Converts 8 bytes to the numerator and denominator
        /// components of an unsigned rational using the current byte aligns
        /// </summary>
        private static uint[] ToURationalFraction(byte[] data)
        {
            var numeratorData = new byte[4];
            var denominatorData = new byte[4];

            Array.Copy(data, numeratorData, 4);
            Array.Copy(data, 4, denominatorData, 0, 4);

            uint numerator = ToUint(numeratorData);
            uint denominator = ToUint(denominatorData);

            return new[] { numerator, denominator };
        }
        /// <summary>
        /// Converts 4 bytes to a uint using the current byte aligns
        /// </summary>
        private static uint ToUint(byte[] data)
        {
            return BitConverter.ToUInt32(data, 0);
        }

    }

}
